﻿using DrawTools;
using DrawTools.Tools;
using DrawTools.Utils;
using Inaction;
using LS.DicomViewer.Common;
using LS.DicomViewer.ViewModels;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace LS.DicomViewer
{
    /// <summary>
    /// DicomViewer.xaml 的交互逻辑
    /// </summary>
    public partial class DicomFrameViewer : UserControl
    {
        private static readonly DependencyProperty FrameTimeProperty;
        private static readonly DependencyProperty PixelSpacingProperty;

        public double? FrameTime
        {
            get { return (double?)GetValue(FrameTimeProperty); }
            set { SetValue(FrameTimeProperty, value); }
        }

        public double? PixelSpacing
        {
            get { return (double?)GetValue(PixelSpacingProperty); }
            set { SetValue(PixelSpacingProperty, value); }
        }

        static DicomFrameViewer()
        {
            FrameTimeProperty = DependencyProperty.Register(nameof(FrameTime), typeof(double?), typeof(DicomFrameViewer));
            PixelSpacingProperty = DependencyProperty.Register(nameof(PixelSpacing), typeof(double?), typeof(DicomFrameViewer));
        }


        #region 变量/属性

        public DicomFrameViewModel ViewModel => this.mainPanel.DataContext as DicomFrameViewModel;

        private static string dicom3DViewerPath;

        private MyDictionary<int, string> drawDataCache = new MyDictionary<int, string>();

        /// <summary>
        /// 画图数据缓存,在画图完成切换当前帧时会保存在此
        /// </summary>
        public MyDictionary<int, string> DrawDataCache { get => drawDataCache; }

        public static readonly DependencyProperty DicomFileProperty = DependencyProperty.Register("DicomFile", typeof(string), typeof(DicomFrameViewer), new PropertyMetadata(string.Empty,
            (a, e) =>
            {
                if (e.NewValue == null || e.NewValue.Equals(string.Empty)) return;
                var view = (DicomFrameViewer)a;
                view.LoadDicomFile(e.NewValue.ToString(), view.FrameTime, view.PixelSpacing);
                view.DicomFileChangedAction?.Invoke(e.NewValue.ToString());
            }
            ));

        /// <summary>
        /// Dicom文件
        /// </summary>
        public string DicomFile
        {
            get => (string)this.GetValue(DicomFileProperty);
            set => this.SetValue(DicomFileProperty, value);
        }

        public Action<string> DicomFileChangedAction { get; set; }


        /// <summary>
        /// dicom文件总帧数
        /// </summary>
        public int? FrameCount => ViewModel?.CurrentDicom?.NumberOfFrames;

        /// <summary>
        /// dicom是否在处理中
        /// </summary>
        public event Action<bool> IsBusyChanged;

        private Process p3d = null;

        #endregion 变量/属性

        /// <summary>
        /// </summary>
        public DicomFrameViewer()
        {
            var dic = new ResourceDictionary();
            try
            {
                dic.Source = new Uri("pack://application:,,,/HandyControl;component/Themes/SkinDark.xaml");
                this.Resources.MergedDictionaries.Add(dic);
            }
            catch { }
            try
            {
                dic.Source = new Uri("pack://application:,,,/HandyControl;component/Themes/Theme.xaml");
                this.Resources.MergedDictionaries.Add(dic);
            }
            catch { }
            try
            {
                dic.Source = new Uri("pack://application:,,,/DrawTools;component/Themes/generic.xaml");
                this.Resources.MergedDictionaries.Add(dic);
            }
            catch { }

            InitializeComponent();

            DpiHelper.GetDpiFromVisual(Application.Current.MainWindow);
        }

        /// <summary>
        /// 加载影像文件
        /// </summary>
        /// <param name="path"></param>
        /// <param name="frameTime"></param>
        /// <param name="pixelSpacing"></param>
        public async void LoadDicomFile(string path, double? frameTime, double? pixelSpacing)
        {
            drawCanvas.Clear();
            drawCanvas.Zoom = 1;
            drawDataCache.Clear();
            await ViewModel.Load(path, frameTime, pixelSpacing);
        }

        /// <summary>
        /// </summary>
        /// <param name="frameIndex"></param>
        /// <param name="points"></param>
        /// <param name="drawToolType">14:闭合曲线，5：矩形</param>
        /// <param name="txt"></param>
        /// <param name="drawIndex"></param>
        public void SetFrameDrawPoints(int frameIndex, List<Point> points, DrawToolType drawToolType = DrawToolType.ClosedLine, string txt = "", bool drawIndex = true)
        {
            if (points.Any() == false) return;

            if (ViewModel.CurrentFrameIndex != frameIndex)
            {
                drawCanvas.Clear();
                drawDataCache.Clear();
                ToFrame(frameIndex);

                if (drawDataCache.ContainsKey(frameIndex))
                {
                    drawDataCache.Remove(frameIndex);
                }
            }
            drawCanvas.Zoom = 1;
            var zoom = drawCanvas.Zoom;
            var dx = 0 * zoom;
            var dy = 0 * zoom;
            var ps = points.Select(p => new Point(p.X * zoom, p.Y * zoom)).ToList();

            DrawGeometryBase drawTool = null;
            if (drawToolType == DrawToolType.ClosedLine)
            {
                ps = ps.Select(p => new Point(p.X + dx, p.Y + dy)).ToList();
                drawCanvas.DrawingToolType = DrawToolType.ClosedLine;
                var closedLineDrawTool = drawTool = new ClosedLineDrawTool(drawCanvas);
                if (drawIndex == false)
                {
                    drawTool.Pen.Brush = new SolidColorBrush(Colors.LightGreen);
                    drawTool.Index = -1;
                    drawTool.ShowIndex = false;
                }
                drawCanvas.AddWorkingDrawTool(closedLineDrawTool);
                drawTool.OnTouchDown(1, ps[0]);
                for (int i = 1; i < ps.Count; i++)
                {
                    var point = ps[i];
                    closedLineDrawTool.OnTouchMove(point);
                }
                closedLineDrawTool.OnTouchUp(ps[0]);
                closedLineDrawTool.OnTouchLeave(ps[0], true);
            }
            var startPoint = ps.FirstOrDefault();
            var endPoint = ps.LastOrDefault();
            if (drawToolType == DrawToolType.Rectangle)
            {
                drawCanvas.DrawingToolType = DrawToolType.Rectangle;
                var rectangleDrawTool = drawTool = new RectangleDrawTool(drawCanvas);
                if (drawIndex == false)
                {
                    drawTool.Pen.Brush = new SolidColorBrush(Colors.LightGreen);
                    drawTool.Index = -1;
                    drawTool.ShowIndex = false;
                }
                drawCanvas.AddWorkingDrawTool(rectangleDrawTool);
                startPoint = new Point(startPoint.X + dx, startPoint.Y + dy);
                endPoint = new Point(startPoint.X + endPoint.X, startPoint.Y + endPoint.Y);
                rectangleDrawTool.OnTouchDown(1, startPoint);
                rectangleDrawTool.OnTouchMove(endPoint);
                rectangleDrawTool.OnTouchLeave(endPoint, true);
            }
            if (!string.IsNullOrEmpty(txt))
            {
                if (DrawerConfig.Instance.TextShowTogether)
                {
                    drawTool.Text = txt;
                    //drawCanvas.RefreshTogetherText();
                }
                else
                {
                    drawCanvas.DrawingToolType = DrawToolType.Text;
                    var textDrawTool = new TextDrawTool(drawCanvas);
                    var point = new Point(startPoint.X, startPoint.Y - 17);
                    textDrawTool.OnTouchDown(1, point);
                    textDrawTool.SetText(txt);
                    textDrawTool.OnTouchDown(0, new Point(point.X - 5, point.Y + 5));
                }
            }
            //drawCanvas.DrawingToolType = DrawToolType.Pointer;
            drawCanvas.Zoom = 1;
        }

        /// <summary>
        /// 切换到指定帧
        /// </summary>
        /// <param name="frameIndex"></param>
        public void ToFrame(int frameIndex)
        {
            drawCanvas.Clear();
            drawCanvas.Zoom = 1;
            ViewModel.SetCurrentFrameIndex(frameIndex);
        }

        public void SaveCurrentDrawDataToFile(string filePath)
        {
            this.drawCanvas.SaveDrawDataToFile(filePath);
        }

        /// <summary>
        /// 保存图片到指定文件
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public string SaveBitmapToFile(string filePath)
        {
            return TryHelper.Try(() =>
             {
                 var path = Path.Combine(ViewModel.ImageFilesDir, ViewModel.CurrentFrameIndex + ".jpeg");
                 var backgroundImage = ReadImage(path);
                 if (backgroundImage == null) return filePath;
                 var frame = this.drawCanvas.ToBitmapFrame(backgroundImage.PixelWidth, backgroundImage.PixelHeight, backgroundImage);
                 if (frame == null) return null;
                 ImageHelper.Save(filePath, frame);
                 return filePath;
             }, 5, 100, $"{this.GetType().Name}.SaveBitmapToFile");
        }


        private static BitmapImage ReadImage(string path)
        {
            if (!File.Exists(path)) return null;
            using (var file = File.OpenRead(path))
            {
                using (var reader = new BinaryReader(file))
                {
                    try
                    {
                        byte[] bytes = reader.ReadBytes((int)file.Length);
                        reader.Close();
                        file.Close();

                        var bitmapImage = new BitmapImage();
                        bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
                        bitmapImage.BeginInit();
                        bitmapImage.StreamSource = new MemoryStream(bytes);
                        bitmapImage.EndInit();
                        return bitmapImage;
                    }
                    catch (Exception)
                    {
                        return null;
                    }
                }
            }
        }
    }
}